package com.ekang.admin.service;

import com.ekang.admin.config.PaySetting;
import com.ekang.wxpay.transfer.bean.TransferBankCardRequest;
import com.ekang.wxpay.transfer.bean.TransferBankCardResponse;
import com.ekang.wxpay.transfer.bean.TransferRequest;
import com.ekang.wxpay.transfer.bean.TransferResponse;
import com.ekang.wxpay.util.*;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.annotation.JsonUnwrapped;
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement;
import com.google.common.base.Joiner;
import org.apache.commons.codec.digest.DigestUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.io.File;
import java.io.FileInputStream;
import java.security.PublicKey;
import java.util.Map;
import java.util.Random;
import java.util.SortedMap;

/**
 * Created by exizhai on 12/2/2015.
 */
@Service
public class Transfers {

    private static Logger logger = LoggerFactory.getLogger(Transfers.class);

    @Autowired
    private PaySetting paySetting;

    /**
     * 获取一定长度的随机字符串
     *
     * @param length 指定字符串长度
     * @return 一定长度的字符串
     */
    public static String getRandomStringByLength(int length) {
        String base = "abcdefghijklmnopqrstuvwxyz0123456789";
        Random random = new Random();
        StringBuffer sb = new StringBuffer();
        for (int i = 0; i < length; i++) {
            int number = random.nextInt(base.length());
            sb.append(base.charAt(number));
        }
        return sb.toString();
    }

    public void setPaySetting(PaySetting paySetting) {
        this.paySetting = paySetting;
    }


    /**
     * MD5编码
     *
     * @param origin 原始字符串
     * @return 经过MD5加密之后的结果
     */
    public static String md5Hex(String origin) {
        return DigestUtils.md5Hex(origin);
    }

    public static String sign(Map<String, Object> map, String key) {
        String str = Joiner.on("&").withKeyValueSeparator("=").join(map);
        str += "&key=" + key;
        return md5Hex(str).toUpperCase();
    }


    /**
     * 企业付款到微信用户零钱
     * amount>1 and amount<20000
     *
     * @param transferRequest
     * @return
     */
    public TransferResponse transfer(TransferRequest transferRequest) {
        TransferRequestWrapper wrapper = new TransferRequestWrapper();
        wrapper.setAppId(paySetting.getAppId());
        wrapper.setMchId(paySetting.getMchId());
        wrapper.setTransferRequest(transferRequest);

        String nonce = getRandomStringByLength(32);
        wrapper.setNonce(nonce);

        SortedMap<String, Object> transferRequestMap = JsonMapper.defaultMapper().getMapper().convertValue(wrapper, SortedMap.class);
        wrapper.setSign(sign(transferRequestMap, paySetting.getMchKey()));

        String url = "https://api.mch.weixin.qq.com/mmpaymkttransfers/promotion/transfers"; //WxEndpoint.get("url.pay.transfer.do");
        try {
            String xml = XmlObjectMapper.defaultMapper().toXml(wrapper);
            logger.info("transfer request: {}", xml);
            FileInputStream inputStream = new FileInputStream(new File(paySetting.getCertPath()));

            String response = WeixinUtil.postXmlWithKey(url, xml, inputStream, paySetting.getMchId());
            logger.info("got response: {}", response);

            TransferResponseWrapper transferResponseWrapper = XmlObjectMapper.defaultMapper().fromXml(response, TransferResponseWrapper.class);
            return transferResponseWrapper.getTransferResponse();
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }


    /**
     * 企业转帐到用户银行卡
     * <p>
     * 接口调用规则：
     * 单商户日限额——单日100w
     * 单次限额——单次5w
     * 单商户给同一银行卡单日限额——单日5w
     *
     * @param transferRequest
     * @return
     */
    public TransferBankCardResponse transfer2BankCard(TransferBankCardRequest transferRequest) throws Exception {

        String encBankAcctName = transferRequest.getEncTrueName();
        String keyfile = "./cert/pcs8.pem"; //
        //RSA工具类提供了，根据加载PKCS8密钥文件的方法
        PublicKey pub = RSAUtil.getPubKey(keyfile, "RSA");
        //rsa是微信付款到银行卡要求我们填充的字符串
        String rsa = "RSA/ECB/OAEPWITHSHA-1ANDMGF1PADDING";
        // 进行加密
        byte[] estr = RSAUtil.encrypt(encBankAcctName.getBytes(), pub, 2048, 11, rsa);   //对银行账号进行base加密
        encBankAcctName = Base64.encode(estr);//并转为base64格式

        transferRequest.setEncTrueName(encBankAcctName);

        estr = RSAUtil.encrypt(transferRequest.getEncBankNo().getBytes(), pub, 2048, 11, rsa);   //对银行账号进行base加密
        transferRequest.setEncBankNo(Base64.encode(estr));
        transferRequest.setMchId(paySetting.getMchId());

        TransferRequestBankCardWrapper wrapper = new TransferRequestBankCardWrapper();
       // wrapper.setAppId(paySetting.getAppId());
        wrapper.setMchId(paySetting.getMchId());
        wrapper.setTransferBankCardRequest(transferRequest);

        String nonce = getRandomStringByLength(32);
        wrapper.setNonce(nonce);


        String url = "https://api.mch.weixin.qq.com/mmpaysptrans/pay_bank";
        try {
            SortedMap<String, Object> transferRequestMap = JsonMapper.defaultMapper().getMapper().convertValue(wrapper, SortedMap.class);
            wrapper.setSign(sign(transferRequestMap, paySetting.getMchKey()));

            String xml = XmlObjectMapper.defaultMapper().toXml(wrapper);
            logger.info("transfer request: {}", xml);
            FileInputStream inputStream = new FileInputStream(new File(paySetting.getCertPath()));

            String response = WeixinUtil.postXmlWithKey(url, xml, inputStream, paySetting.getMchId());
            logger.info("got response: {}", response);

            TransferBankCardResponseWrapper transferResponseWrapper = XmlObjectMapper.defaultMapper().fromXml(response, TransferBankCardResponseWrapper.class);
            return transferResponseWrapper.getTransferBankCardResponse();
        } catch (Exception e) {
            e.printStackTrace();

            throw new RuntimeException(e);
        }
    }


    @JacksonXmlRootElement(localName = "xml")
    public static class TransferRequestWrapper {

        @JsonUnwrapped
        private TransferRequest transferRequest;

        @JsonProperty("mch_appid")
        private String appId;

        @JsonProperty("mchid")
        private String mchId;

        @JsonInclude(JsonInclude.Include.NON_NULL)
        private String sign;

        @JsonProperty("nonce_str")
        private String nonce;

        public TransferRequest getTransferRequest() {
            return transferRequest;
        }

        public void setTransferRequest(TransferRequest transferRequest) {
            this.transferRequest = transferRequest;
        }

        public String getAppId() {
            return appId;
        }

        public void setAppId(String appId) {
            this.appId = appId;
        }

        public String getMchId() {
            return mchId;
        }

        public void setMchId(String mchId) {
            this.mchId = mchId;
        }

        public String getSign() {
            return sign;
        }

        public void setSign(String sign) {
            this.sign = sign;
        }

        public String getNonce() {
            return nonce;
        }

        public void setNonce(String nonce) {
            this.nonce = nonce;
        }
    }

    @JacksonXmlRootElement(localName = "xml")
    public static class TransferResponseWrapper {

        @JsonUnwrapped
        private TransferResponse transferResponse;

        public TransferResponse getTransferResponse() {
            return transferResponse;
        }

        public void setTransferResponse(TransferResponse transferResponse) {
            this.transferResponse = transferResponse;
        }
    }

    @JacksonXmlRootElement(localName = "xml")
    public static class QueryTransferResultRequestWrapper {

        @JsonProperty("partner_trade_no")
        private String partnerTradeNo;

        @JsonProperty("appid")
        private String appId;

        @JsonProperty("mch_id")
        private String mchId;

        @JsonInclude(JsonInclude.Include.NON_NULL)
        private String sign;

        @JsonProperty("nonce_str")
        private String nonce;

        public String getPartnerTradeNo() {
            return partnerTradeNo;
        }

        public void setPartnerTradeNo(String partnerTradeNo) {
            this.partnerTradeNo = partnerTradeNo;
        }

        public String getAppId() {
            return appId;
        }

        public void setAppId(String appId) {
            this.appId = appId;
        }

        public String getMchId() {
            return mchId;
        }

        public void setMchId(String mchId) {
            this.mchId = mchId;
        }

        public String getSign() {
            return sign;
        }

        public void setSign(String sign) {
            this.sign = sign;
        }

        public String getNonce() {
            return nonce;
        }

        public void setNonce(String nonce) {
            this.nonce = nonce;
        }
    }


    @JacksonXmlRootElement(localName = "xml")
    public static class TransferRequestBankCardWrapper {

        @JsonUnwrapped
        private TransferBankCardRequest transferBankCardRequest;

//        @JsonProperty("mch_appid")
//        private String appId;

        @JsonProperty("mch_id")
        private String mchId;

        @JsonInclude(JsonInclude.Include.NON_NULL)
        private String sign;

        @JsonProperty("nonce_str")
        private String nonce;


        public TransferBankCardRequest getTransferBankCardRequest() {
            return transferBankCardRequest;
        }

        public void setTransferBankCardRequest(TransferBankCardRequest transferRequest) {
            this.transferBankCardRequest = transferRequest;
        }

//        public String getAppId() {
//            return appId;
//        }
//
//        public void setAppId(String appId) {
//            this.appId = appId;
//        }

        public String getMchId() {
            return mchId;
        }

        public void setMchId(String mchId) {
            this.mchId = mchId;
        }

        public String getSign() {
            return sign;
        }

        public void setSign(String sign) {
            this.sign = sign;
        }

        public String getNonce() {
            return nonce;
        }

        public void setNonce(String nonce) {
            this.nonce = nonce;
        }


    }

    @JacksonXmlRootElement(localName = "xml")
    public static class TransferBankCardResponseWrapper {

        @JsonUnwrapped
        private TransferBankCardResponse transferResponse;

        public TransferBankCardResponse getTransferBankCardResponse() {
            return transferResponse;
        }

        public void setTransferBankCardResponse(TransferBankCardResponse transferResponse) {
            this.transferResponse = transferResponse;
        }
    }

}
